
/*
Redis Installation on Ubuntu:
---------------------------
1. Update package list:
   $ sudo apt update

2. Install Redis:
   $ sudo apt install redis-server

3. Verify installation:
   $ redis-cli --version
   $ redis-server --version

4. Start Redis service:
   $ sudo systemctl start redis-server

5. Enable Redis to start on boot:
   $ sudo systemctl enable redis-server

6. Check Redis status:
   $ sudo systemctl status redis-server

Common Redis Commands:
-------------------
1. Basic Operations:
   - SET key value        : Set key to hold string value
   - GET key              : Get value of key
   - DEL key             : Delete a key
   - EXISTS key          : Check if key exists
   - EXPIRE key seconds  : Set key expiration time
   - TTL key            : Get remaining time to live of a key

2. List Operations:
   - LPUSH key value    : Insert value at the head of list
   - RPUSH key value    : Insert value at the tail of list
   - LRANGE key start stop : Get list elements from start to stop
   - LPOP key           : Remove and get first element
   - RPOP key          : Remove and get last element

3. Set Operations:
   - SADD key member   : Add member to set
   - SMEMBERS key     : Get all members of set
   - SREM key member  : Remove member from set
   - SISMEMBER key member : Test if member is in set

4. Hash Operations:
   - HSET key field value : Set field in hash stored at key
   - HGET key field      : Get value of field in hash
   - HGETALL key        : Get all fields and values in hash
   - HDEL key field     : Delete field from hash

5. Utility Commands:
   - KEYS pattern      : Find all keys matching pattern
   - FLUSHDB          : Remove all keys from current database
   - INFO             : Get server information and statistics
   - SELECT index     : Change the selected database
   - MONITOR          : Debug command to see all requests
   - CLIENT LIST      : Get list of client connections

6. Connection Management:
   - AUTH password    : Authenticate to server
   - PING            : Test connection (server responds with PONG)
   - QUIT            : Close connection

Redis Configuration:
------------------
- Config file location: /etc/redis/redis.conf
- Default port: 6379
- Default bind address: 127.0.0.1 (localhost)

Security Best Practices:
----------------------
1. Change default port
2. Set strong password using: requirepass in redis.conf
3. Disable dangerous commands
4. Enable protected-mode
5. Use firewall rules to restrict access
6. Regular backups using SAVE or BGSAVE commands
*/

#include <hiredis/hiredis.h>
#include <iostream>
#include <string>
#include <vector>
#include <memory>
#include <stdexcept>

// Redis连接包装类 - RAII方式管理Redis连接
class RedisConnection {
public:
    RedisConnection(const char* host = "127.0.0.1", int port = 6379) {
        // 建立Redis连接
        context_ = redisConnect(host, port);
        if (context_ == nullptr || context_->err) {
            if (context_) {
                std::string error = context_->errstr;
                redisFree(context_);
                throw std::runtime_error("Redis连接错误: " + error);
            } else {
                throw std::runtime_error("Redis连接分配失败");
            }
        }
    }

    ~RedisConnection() {
        if (context_) {
            redisFree(context_);
        }
    }

    // 禁止拷贝
    RedisConnection(const RedisConnection&) = delete;
    RedisConnection& operator=(const RedisConnection&) = delete;

    // 获取原始连接
    redisContext* get() { return context_; }

private:
    redisContext* context_;
};

// Redis命令执行器 - 处理Redis命令执行和结果解析
class RedisCommander {
public:
    explicit RedisCommander(RedisConnection& conn) : conn_(conn) {}

    // 执行命令并检查结果
    redisReply* execute(const char* format, ...) {
        va_list args;
        va_start(args, format);
        redisReply* reply = (redisReply*)redisvCommand(conn_.get(), format, args);
        va_end(args);

        if (reply == nullptr) {
            throw std::runtime_error("Redis命令执行失败");
        }
        return reply;
    }

    // 自动释放redisReply的智能指针
    using ReplyPtr = std::unique_ptr<redisReply, decltype(&freeReplyObject)>;
    
    ReplyPtr executeWithSmartPtr(const char* format, ...) {
        va_list args;
        va_start(args, format);
        redisReply* reply = (redisReply*)redisvCommand(conn_.get(), format, args);
        va_end(args);

        if (reply == nullptr) {
            throw std::runtime_error("Redis命令执行失败");
        }
        return ReplyPtr(reply, freeReplyObject);
    }

private:
    RedisConnection& conn_;
};

// 示例：用户会话管理类
class UserSessionManager {
public:
    explicit UserSessionManager(RedisConnection& conn) : commander_(conn) {}

    // 设置用户会话
    void setUserSession(const std::string& userId, const std::string& sessionData) {
        // 使用SETEX命令设置带过期时间的会话数据（1小时）
        auto reply = commander_.executeWithSmartPtr(
            "SETEX user:session:%s 3600 %s", 
            userId.c_str(), 
            sessionData.c_str()
        );
        
        if (reply->type == REDIS_REPLY_ERROR) {
            throw std::runtime_error("设置用户会话失败");
        }
    }

    // 获取用户会话
    std::string getUserSession(const std::string& userId) {
        auto reply = commander_.executeWithSmartPtr(
            "GET user:session:%s", 
            userId.c_str()
        );

        if (reply->type == REDIS_REPLY_STRING) {
            return std::string(reply->str, reply->len);
        }
        return "";
    }

    // 删除用户会话
    void deleteUserSession(const std::string& userId) {
        auto reply = commander_.executeWithSmartPtr(
            "DEL user:session:%s", 
            userId.c_str()
        );

        if (reply->type == REDIS_REPLY_ERROR) {
            throw std::runtime_error("删除用户会话失败");
        }
    }

private:
    RedisCommander commander_;
};

// 示例：计数器实现
class RedisCounter {
public:
    explicit RedisCounter(RedisConnection& conn) : commander_(conn) {}

    // 增加计数
    int64_t increment(const std::string& key, int64_t by = 1) {
        auto reply = commander_.executeWithSmartPtr(
            "INCRBY counter:%s %lld", 
            key.c_str(), 
            by
        );

        if (reply->type == REDIS_REPLY_INTEGER) {
            return reply->integer;
        }
        throw std::runtime_error("增加计数失败");
    }

    // 获取计数
    int64_t get(const std::string& key) {
        auto reply = commander_.executeWithSmartPtr(
            "GET counter:%s", 
            key.c_str()
        );

        if (reply->type == REDIS_REPLY_STRING) {
            return std::stoll(reply->str);
        }
        return 0;
    }

private:
    RedisCommander commander_;
};

// 示例：简单的缓存实现
class RedisCache {
public:
    explicit RedisCache(RedisConnection& conn) : commander_(conn) {}

    // 设置缓存（带过期时间）
    void set(const std::string& key, const std::string& value, int expireSeconds) {
        auto reply = commander_.executeWithSmartPtr(
            "SETEX cache:%s %d %s", 
            key.c_str(), 
            expireSeconds,
            value.c_str()
        );

        if (reply->type == REDIS_REPLY_ERROR) {
            throw std::runtime_error("设置缓存失败");
        }
    }

    // 获取缓存
    std::string get(const std::string& key) {
        auto reply = commander_.executeWithSmartPtr(
            "GET cache:%s", 
            key.c_str()
        );

        if (reply->type == REDIS_REPLY_STRING) {
            return std::string(reply->str, reply->len);
        }
        return "";
    }

    // 检查键是否存在
    bool exists(const std::string& key) {
        auto reply = commander_.executeWithSmartPtr(
            "EXISTS cache:%s", 
            key.c_str()
        );

        return reply->type == REDIS_REPLY_INTEGER && reply->integer == 1;
    }

private:
    RedisCommander commander_;
};

// 示例：Redis列表操作
class RedisList {
public:
    explicit RedisList(RedisConnection& conn) : commander_(conn) {}

    // 添加元素到列表头部
    void pushFront(const std::string& listName, const std::string& value) {
        auto reply = commander_.executeWithSmartPtr(
            "LPUSH list:%s %s", 
            listName.c_str(), 
            value.c_str()
        );

        if (reply->type == REDIS_REPLY_ERROR) {
            throw std::runtime_error("添加列表元素失败");
        }
    }

    // 获取列表范围内的元素
    std::vector<std::string> getRange(const std::string& listName, int start, int end) {
        auto reply = commander_.executeWithSmartPtr(
            "LRANGE list:%s %d %d", 
            listName.c_str(), 
            start, 
            end
        );

        std::vector<std::string> result;
        if (reply->type == REDIS_REPLY_ARRAY) {
            for (size_t i = 0; i < reply->elements; i++) {
                result.emplace_back(reply->element[i]->str, reply->element[i]->len);
            }
        }
        return result;
    }

private:
    RedisCommander commander_;
};

int main() {
    try {
        // 创建Redis连接
        RedisConnection conn("127.0.0.1", 6379);
        
        // 1. 演示会话管理
        {
            std::cout << "\n=== 会话管理演示 ===" << std::endl;
            UserSessionManager sessionMgr(conn);
            
            // 设置会话
            sessionMgr.setUserSession("user123", "{\"lastLogin\":\"2024-03-20\"}");
            
            // 获取会话
            std::string session = sessionMgr.getUserSession("user123");
            std::cout << "用户会话数据: " << session << std::endl;
            
            // 删除会话
            sessionMgr.deleteUserSession("user123");
        }

        // 2. 演示计数器
        {
            std::cout << "\n=== 计数器演示 ===" << std::endl;
            RedisCounter counter(conn);
            
            // 增加计数
            int64_t count = counter.increment("visitors", 1);
            std::cout << "访问计数: " << count << std::endl;
            
            // 再次增加并获取
            count = counter.increment("visitors", 2);
            std::cout << "更新后的访问计数: " << count << std::endl;
        }

        // 3. 演示缓存
        {
            std::cout << "\n=== 缓存演示 ===" << std::endl;
            RedisCache cache(conn);
            
            // 设置缓存（30秒过期）
            cache.set("user:profile:123", "{\"name\":\"张三\",\"age\":30}", 30);
            
            // 获取缓存
            std::string cached = cache.get("user:profile:123");
            std::cout << "缓存的用户配置: " << cached << std::endl;
            
            // 检查是否存在
            bool exists = cache.exists("user:profile:123");
            std::cout << "缓存是否存在: " << (exists ? "是" : "否") << std::endl;
        }

        // 4. 演示列表操作
        {
            std::cout << "\n=== 列表操作演示 ===" << std::endl;
            RedisList list(conn);
            
            // 添加元素
            list.pushFront("recent_users", "user1");
            list.pushFront("recent_users", "user2");
            list.pushFront("recent_users", "user3");
            
            // 获取列表元素
            auto users = list.getRange("recent_users", 0, -1);
            std::cout << "最近的用户列表:" << std::endl;
            for (const auto& user : users) {
                std::cout << "- " << user << std::endl;
            }
        }

    } catch (const std::exception& e) {
        std::cerr << "错误: " << e.what() << std::endl;
        return 1;
    }

    return 0;
}